#include <jni.h>
#include <stdlib.h>
#include <android/log.h>
#include "fmod.hpp"
#include "fmod_errors.h"
#include "soundtouch.h"

using namespace soundtouch;
using namespace FMOD;

#ifdef __cplusplus
extern "C" {
#endif

System *gSystem;
FMOD_RESULT result;
Channel *gChannel;
Sound *gSound;
DSP *gDSPPitchShift;
float gFrequency;

void FMODErrorCheck(FMOD_RESULT result, const char * file, int line) {
	if (result != FMOD_OK) {
		__android_log_print(ANDROID_LOG_ERROR, "fmod", "FMOD error! (%d) %s\n%s:%d", result, FMOD_ErrorString(result),
				file, line);
		exit(-1);
	}
}

void FMODInfo(const char * message) {
	__android_log_print(ANDROID_LOG_INFO, "fmod", "%s", message);
}

JNIEXPORT void JNICALL Java_com_bhprod_guitartrack_MainActivity_cBegin(JNIEnv *env, jobject thiz, jstring filePath) {
	const char *cFilePath = env->GetStringUTFChars(filePath, NULL);

	result = System_Create(&gSystem);
	FMODErrorCheck(result, __FILE__, __LINE__);

	FMODInfo("Create system");

	result = gSystem->init(32, FMOD_INIT_NORMAL, 0);
	FMODErrorCheck(result, __FILE__, __LINE__);

	FMODInfo("init");

	result = gSystem->createStream(cFilePath, FMOD_DEFAULT | FMOD_LOWMEM, 0, &gSound);
	FMODErrorCheck(result, __FILE__, __LINE__);

	FMODInfo("Create stream");

	env->ReleaseStringUTFChars(filePath, cFilePath);

	FMODInfo("Quit begin");
}

JNIEXPORT void JNICALL Java_com_bhprod_guitartrack_MainActivity_cUpdate(JNIEnv *env, jobject thiz) {
	result = gSystem->update();
	FMODErrorCheck(result, __FILE__, __LINE__);
}

JNIEXPORT void JNICALL Java_com_bhprod_guitartrack_MainActivity_cEnd(JNIEnv *env, jobject thiz) {
	result = gSound->release();
	FMODErrorCheck(result, __FILE__, __LINE__);

	result = gDSPPitchShift->release();
	FMODErrorCheck(result, __FILE__, __LINE__);

	result = gSystem->release();
	FMODErrorCheck(result, __FILE__, __LINE__);
}

JNIEXPORT void JNICALL Java_com_bhprod_guitartrack_MainActivity_cPlaySound(JNIEnv *env, jobject thiz) {

	FMODInfo("Start playSound");

	result = gSystem->playSound(FMOD_CHANNEL_FREE, gSound, 0, &gChannel);
	FMODErrorCheck(result, __FILE__, __LINE__);

	gChannel->getFrequency(&gFrequency);

	result = gSystem->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &gDSPPitchShift);
	FMODErrorCheck(result, __FILE__, __LINE__);

	result = gDSPPitchShift->setParameter(FMOD_DSP_PITCHSHIFT_PITCH, 1);
	FMODErrorCheck(result, __FILE__, __LINE__);

	result = gSystem->addDSP(gDSPPitchShift, 0);
	FMODErrorCheck(result, __FILE__, __LINE__);

	FMODInfo("End playSound");

}

JNIEXPORT void JNICALL Java_com_bhprod_guitartrack_MainActivity_cPauseSound(JNIEnv *env, jobject thiz, int paused) {
	FMODInfo("Start pauseSound");

	if (gChannel) {
		result = gChannel->setPaused(paused);
		FMODErrorCheck(result, __FILE__, __LINE__);
	}

	FMODInfo("End pauseSound");

}

JNIEXPORT jint JNICALL Java_com_bhprod_guitartrack_MainActivity_cGetPosition(JNIEnv *env, jobject thiz) {
	unsigned int position = 0;

	if (gChannel) {
		result = gChannel->getPosition(&position, FMOD_TIMEUNIT_MS);
		if (result != FMOD_ERR_INVALID_HANDLE && result != FMOD_ERR_CHANNEL_STOLEN) {
			FMODErrorCheck(result, __FILE__, __LINE__);
		}
	}

	return position;
}

JNIEXPORT void JNICALL Java_com_bhprod_guitartrack_MainActivity_cSetPosition(JNIEnv *env, jobject thiz, int position) {

	FMODInfo("Start setPosition");

	if (gChannel) {
		result = gChannel->setPosition(position, FMOD_TIMEUNIT_MS);
		if (result != FMOD_ERR_INVALID_HANDLE && result != FMOD_ERR_CHANNEL_STOLEN) {
			FMODErrorCheck(result, __FILE__, __LINE__);
		}
	}

	FMODInfo("End setPosition");

}

JNIEXPORT jint JNICALL Java_com_bhprod_guitartrack_MainActivity_cGetLength(JNIEnv *env, jobject thiz) {
	unsigned int length = 0;

	FMODInfo("Start getLength");

	if (gSound) {
		result = gSound->getLength(&length, FMOD_TIMEUNIT_MS);
		FMODErrorCheck(result, __FILE__, __LINE__);
	}

	FMODInfo("End getLength");

	return length;
}

JNIEXPORT jstring JNICALL Java_com_bhprod_guitartrack_MainActivity_cGetTitle(JNIEnv *env, jobject thiz) {
	FMOD_TAG tag;
	gSound->getTag("TITLE", 0, &tag);

	jstring jTitle = env->NewStringUTF((const char*) tag.data);

	return jTitle;
}

JNIEXPORT void JNICALL Java_com_bhprod_guitartrack_MainActivity_cSetSpeed(JNIEnv *env, jobject thiz, float speed) {
	FMODInfo("Start setSpeed");

	if (gChannel) {
		FMODInfo("gChannel OK");
	} else {
		FMODInfo("gChannel KO");
	}
	if (gDSPPitchShift) {
		FMODInfo("gDSPPitchShift OK");
	} else {
		FMODInfo("gDSPPitchShift KO");
	}

	if (gChannel && gDSPPitchShift) {
		gChannel->setFrequency(gFrequency * (1 / speed));

		__android_log_print(ANDROID_LOG_INFO, "fmod", "frequence courante : %f", gFrequency * speed);

		result = gDSPPitchShift->setParameter(FMOD_DSP_PITCHSHIFT_PITCH, speed);
		FMODErrorCheck(result, __FILE__, __LINE__);

		__android_log_print(ANDROID_LOG_INFO, "fmod", "Pitch courant : %f", speed);
	}

	FMODInfo("End setSpeed");

}

#ifdef __cplusplus
}
#endif
